package com.gitee.huanminabc.jfastcache;


import com.gitee.huanminabc.jfastcache.enums.CacheEnum;
import com.gitee.huanminabc.jfastcache.local.AbstractLocalCache;
import com.gitee.huanminabc.jfastcache.local.LocalCache;
import com.gitee.huanminabc.jfastcache.memory.MemoryCache;

import java.util.function.Supplier;

public class CacheSupport<V> implements Cache<String, V> {
    private final CacheEnum cacheEnum;
    private  Cache<String, V> cache;

    private CacheSupport(String key,int capacity, int timeout,CacheEnum cacheEnum) {
        this.cacheEnum = cacheEnum;
        if (this.cacheEnum == CacheEnum.LOCAL) {
            this.cache = new LocalCache<>(key, capacity, timeout);
        } else if (cacheEnum == CacheEnum.MEMORY) {
            this.cache = new MemoryCache<>(capacity, timeout);
        }
    }

    public static <V> CacheSupport<V> createLocalCache(String key,int capacity, int timeout) {
        return new CacheSupport<>(key,capacity, timeout,CacheEnum.LOCAL);
    }
    public static <V> CacheSupport<V> createLocalCache( String key,int timeout) {
        //使用默认容量10000，timeout参数
        return new CacheSupport<>(key, 10000, timeout, CacheEnum.LOCAL);
    }

    public static <V> CacheSupport<V> createMemoryCache(int capacity, int timeout) {
        return new CacheSupport<>(null,capacity, timeout, CacheEnum.MEMORY);
    }

    public static <V> CacheSupport<V> createMemoryCache(int capacity) {
        return new CacheSupport<>(null,capacity, -1, CacheEnum.MEMORY);
    }


    @Override
    public boolean put(String key, V value) {
       return cache.put(key, value);
    }

    @Override
    public boolean put(String key, V value, long timeout) {
        return cache.put(key, value, timeout);
    }

    @Override
    public V get(String key) {
        return cache.get(key);
    }

    @Override
    public V remove(String key) {
        return cache.remove(key);
    }

    @Override
    public void clear() {
        cache.clear();
    }

    @Override
    public void pruneCache() {
        cache.pruneCache();
    }
    //key加锁,可以让同一个key在一段时间内只执行一次,其他的丢弃 线程安全
    public V discard(String key, int timeInterval,Supplier<V> function) {
        return ((AbstractCache<V>) cache).discard(key, timeInterval, function);
    }

    public V discard(String key, Supplier<V> function) {
        return ((AbstractCache<V>) cache).discard(key, function);
    }
    
    public void discard(String key, Runnable consumer) {
        ((AbstractCache<V>) cache).discard(key, consumer);
    }


    //获取缓存的同时添加, 意思就是如果缓存不存在, 那么就添加, 如果存在, 那么就返回
    // 如果缓存不存在，返回null并放入新值；如果存在，返回旧值
    // 注意：此方法在高并发场景下，同一个key的function可能被执行多次
    // 如果需要确保function只执行一次，请使用discard方法
    public V getAndPut(String key, Supplier<V> function) {
        V v = this.get(key);
        if (v == null) {
            V newValue = function.get();
            this.put(key, newValue);
            return null; // 第一次返回null，表示之前没有值
        }
        return v; // 返回旧值
    }

    /**
     * 关闭缓存（仅对本地缓存有效，用于释放文件锁）
     */
    public void close() {
        if (cacheEnum == CacheEnum.LOCAL && cache instanceof AbstractLocalCache) {
            ((AbstractLocalCache<?>) cache).close();
        }
    }


}
